﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GeneticAlgorithm.Demo.Common.Algorithm
{
    internal class Gene : ICloneable
    {
        public Gene() { }
        public Gene(double displayValue)
        {
            this.DisplayValue = displayValue;
        }
        public double Fitness { get; set; }
        public double Y { get; set; }
        /// <summary>
        /// 表现型
        /// </summary>
        public double DisplayValue { get; set; }
        /// <summary>
        /// 基因型
        /// </summary>
        public byte[] Genotype { get; set; }

        public object Clone()
        {
           var clone = this.MemberwiseClone() as Gene;
            byte[] newGenotype = new byte[Genotype.Length];
            Array.Copy(Genotype, newGenotype, Genotype.Length);
            clone.Genotype= newGenotype;
            return clone;
        }

        public byte[] Code(double lower, double upper,byte accuracy, int geneMinLength)
        {
            double lowerBound = lower;
            double upperBound = upper;
            double divisions = (upperBound - lowerBound) * Math.Pow(10, accuracy);
            long value = (long)((DisplayValue - lowerBound) / (upperBound - lowerBound) * divisions);
            byte[] binaryArray = new byte[geneMinLength];
            for (int i = 0; i < geneMinLength; i++)
            {
                binaryArray[i] = (byte)((value >> i) & 1);
            }
            Genotype = binaryArray;
            return binaryArray;
        }
        public double Decode(double lower, double upper, byte accuracy)
        {
            double lowerBound = lower;
            double upperBound = upper;
            double divisions = (upperBound - lowerBound) * Math.Pow(10, accuracy);
            long b = 0;
            for (int i = 0; i < Genotype.Length; i++)
            {
                b |= (long)Genotype[i] << i;
            }
            this.DisplayValue = b / divisions * (upperBound - lowerBound) + lowerBound;

            return b;
        }
        public override string ToString()
        {
            return $"DisplayValue={DisplayValue}\r\nFitness={Fitness}\r\nY={Y}\r\nGenotype={string.Join("", Genotype)}";
        }
    }
}
